﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using System.Linq.Expressions;
using DR.Repository.Abstract;

namespace DR.Repository.Concrete.LinqToSql
{
    public abstract class LinqToSqlBaseRepository<E, K> : IRepository<E, K> where E: class
    {
        private readonly string _connectionString;

        public LinqToSqlBaseRepository(string connectionString)
        {
            this._connectionString = connectionString;
        }

        protected DataContext CreateDataContext()
        {
            DataContext dataContext = new DataContext(this._connectionString);
            dataContext.LoadOptions = GetDefaultDataLoadOptions();
            return dataContext;
        }

        protected abstract Table<E> GetDataTable(DataContext dataContext);
        protected abstract Expression<Func<E, bool>> GetIDQuery(K id);
        protected abstract K GetEntityID(E entity);
     
        protected virtual DataLoadOptions GetDefaultDataLoadOptions()
        {
            return new DataLoadOptions();
        }

        public E SelectByID(K id)
        {
            using (DataContext dc = CreateDataContext())
            {
                return GetDataTable(dc).SingleOrDefault(GetIDQuery(id));
            }
        }

        public IList<E> SelectAll()
        {
            using (DataContext dc = CreateDataContext())
            {
                return GetDataTable(dc).ToList();
            }
        }

        public IList<E> SelectAll(int startIndex, int maxSize)
        {
            using (DataContext dc = CreateDataContext())
            {
                return GetDataTable(dc).Skip(startIndex).Take(maxSize).ToList(); 
            }
        }

        public int GetCount()
        {
            using (DataContext dc = CreateDataContext())
            {
                return GetDataTable(dc).Count();
            }
        }

        public E Update(E entity)
        {
            using (DataContext dc = CreateDataContext())
            {
                E old = SelectByID(GetEntityID(entity));
                GetDataTable(dc).Attach(entity, old);
                dc.SubmitChanges();
                return entity;
            }
        }

        public E Insert(E entity)
        {
            using (DataContext dc = CreateDataContext())
            {
                GetDataTable(dc).InsertOnSubmit(entity);
                dc.SubmitChanges();
                return entity;
            }
        }

        public void Delete(K id)
        {
            using (DataContext dc = CreateDataContext())
            {
                E entity = GetDataTable(dc).Single(GetIDQuery(id));
                GetDataTable(dc).DeleteOnSubmit(entity);
                dc.SubmitChanges();
            }
        }

    }
}
